home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 May: Tool Chest / Developer CD Series May 1996 (Tool Chest) (Apple Computer) (1996).iso / Sample Code / System 7.0 Samples / Edition Manager / Publish.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-18  |  30.5 KB  |  750 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------
  2.  *
  3.  *  Apple Developer Technical Support
  4.  *
  5.  *  Edition publishing routines
  6.  *
  7.  *  Program:    EditionSample
  8.  *  File:       Publish.c - C Source
  9.  *
  10.  *  by:         C.K. Haun <TR>
  11.  *
  12.  *  Copyright © 1990,1991 Apple Computer, Inc.
  13.  *  All rights reserved.
  14.  *
  15.  *------------------------------------------------------------------------------
  16.  * Publish handles most of the publishing housekeeping.  There is (are) 
  17.  * some routines that are common to both publishing and subscribing, they 
  18.  * are located in Subscribe.c 
  19.  *----------------------------------------------------------------------------*/
  20. #define __PUBLISH__
  21.  
  22. #pragma segment Publish
  23. #pragma load "EdSampheaders"                                /* see the Buildheaders.c file */
  24.  
  25. #include "EdSampdefines.h"
  26.  
  27. /* prototypes */
  28. OSErr CreatePublisher(OSType typeToMake,Boolean fromEvent,AliasHandle theAlias);
  29. PicHandle MyMakePicture(Rect *thisRect);
  30. OSErr MyWriteSection(SectionHandle secHandle, Handle theData, OSType theType);
  31. OSErr MyUpdateEdition(SectionHandle theSection);
  32. void StorePublisher(windowCHandle shortName, SectionHandle storeSection, Rect *inRect, textSectionHandle textIn, OSType typeIn);
  33. WindowPtr FindSection(SectionHandle inSection);
  34. pascal OSErr AEWriteSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  35. pascal OSErr AECreatePubHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  36. pascal short ExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr);
  37. pascal Boolean ExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr);
  38. textSectionHandle GetTextSection(windowCHandle shortName, SectionType what);
  39. textSectionHandle TextSectionFromSecHandle(SectionHandle theSection);
  40.  
  41. /* external references */
  42. extern void ShowMe(Str255 in, OSErr aevtErr);
  43. extern void ChangePlane(WindowPtr twindow);
  44. extern void MyCancelSection(SectionHandle inSection, WindowPtr theWindow);
  45. extern OSErr GetSectionHandleFromEvent(AppleEvent *AEin, SectionHandle *theSection);
  46. extern Rect selectRect;
  47. extern WindowPtr gCurrentWindow;
  48. extern void SetMyCursor(short myCurs);
  49. extern void SwitchChecks(short itemNow);
  50. extern void AppendString(Str255 target, Str255 appendIt);
  51. extern Boolean gShowPub;
  52. extern Boolean gShowSub;
  53. extern Boolean gHasSelection;
  54. extern ProcessSerialNumber gOurSN;                          /* serial number of this process (us) */
  55. extern Boolean gShowingAll;
  56. /* globals */
  57. SectionHandle gSecHandle;
  58. EditionRefNum gEdRefNum;
  59. EditionContainerSpec gEdSpec;
  60. unsigned long gSectionID = 1;
  61.  
  62. /*  CreatePublisher takes the currently selected area in the current window 
  63. *       and creates an edition.  It starts by setting up some default data 
  64. *       structures and creating a preview picture.  
  65. *       Then the user is prompted for a location and name for the publisher
  66. *       with the NewPublisherDialog.  If the user clicks OK, then the edition
  67. *       is created and the section handle and rectangle for this edition is
  68. *       stored in my data structure for this window, and the first edition
  69. *       is written out.
  70. */
  71.  
  72. OSErr CreatePublisher(OSType typeToMake,Boolean fromEvent,AliasHandle theAlias)
  73. {
  74.     NewPublisherReply myreply;
  75.     Handle theData;
  76.     Rect currentRect;
  77.     textSectionHandle pubText;
  78.     Str31 addPub;
  79.     static pubCounter;
  80.     OSErr myErr;
  81.     windowCHandle shortName;
  82.     extern Point expPoint;
  83.     extern Boolean gExpanded;
  84.     /* we're publishing from the current, topmost window */
  85.     shortName = (windowCHandle)GetWRefCon(gCurrentWindow);
  86.     HLock((Handle)shortName);
  87.     switch (typeToMake) {
  88.         case 'PICT':
  89.             currentRect = (*shortName)->selectionRect;
  90.             /* take the rectangle we currently have selected, and make it a picture */
  91.             InsetRect(¤tRect, 4, 4);                  /* take away the bordering outset */
  92.             theData = (Handle)MyMakePicture(¤tRect);      /* my function to make a PICT */
  93.             /* Set up the reply record for the publisher dialog.  */
  94.             myreply.usePart = false;                        /* must be false */
  95.             myreply.previewFormat = 'PICT';                 /* type of data we're publishing */
  96.             myreply.preview = theData;                      /* handle to the pict data */
  97.             break;
  98.         case 'TEXT':
  99.             /* make text preview */
  100.             myreply.usePart = false;                        /* must be false */
  101.             myreply.previewFormat = 'TEXT';                 /* type of data we're publishing */
  102.             pubText = GetTextSection(shortName, stPublisher);
  103.             HLock((Handle)pubText);
  104.             theData = (*pubText)->theText;                  /* duplicate the text for our preview */
  105.             HandToHand(&theData);
  106.             if (GetHandleSize(theData) > 200)
  107.                 SetHandleSize(theData, 200);
  108.             
  109.             myreply.preview = theData;
  110.             break;
  111.         case kCustomType:
  112.             break;
  113.     }
  114.     GetLastEditionContainerUsed(&gEdSpec);                  /* get a new edition containter.  */
  115.     /* this call gives us a duplicate of the last used, or if none used last, gives */
  116.     /* us a default container */
  117.     /* BY THE WAY - the 'last used' means the last used by the Edition Manager, not */
  118.     /* by your application, so if you don't specify a default name then the */
  119.     /* name that comes up as the default for the edition may be the last */
  120.     /* name used by another application, or from the last time your */
  121.     /* application was run.  So if you are concerned about this (like you */
  122.     /* think it may confuse the user) set your own default */
  123.     /* As a sidelight (and not guarenteed) an alias to the last edition container used */
  124.     /* is stored in the 'Preferences' folder in the system folder */
  125.     myreply.container = gEdSpec;                            /* put our file spec in the container to be filled */
  126.     /* now set the default name to be the same as the window plus a count */
  127.     GetWTitle(gCurrentWindow, &myreply.container.theFile.name);
  128.     GetIndString(addPub, kGeneralStrings, 1);
  129.     AppendString(myreply.container.theFile.name, addPub);
  130.     NumToString((long)((*shortName)->numPubs) + 1, addPub);
  131.     AppendString(myreply.container.theFile.name, addPub);
  132.     if(!fromEvent){
  133.     if (!gExpanded)
  134.         myErr = NewPublisherDialog(&myreply);               /* run the dialog */
  135.     else
  136.     {
  137.         ExpDlgHookUPP dhUPP = NewExpDlgHookProc(ExpOptHook);
  138.         ExpModalFilterUPP mfUPP = NewExpModalFilterProc(ExpOptFilter);
  139.         myErr = NewPublisherExpDialog(&myreply, expPoint, kExpandedDITL, dhUPP, mfUPP, nil);
  140.         DisposeRoutineDescriptor(dhUPP);
  141.         DisposeRoutineDescriptor(mfUPP);
  142.     }
  143.     
  144.     if (myErr) {
  145.         ShowMe("\pPubisher dialog", myErr);
  146.         return;
  147.     }
  148.     if (myreply.canceled) {                                 /* they canceled.  release memory, reset our */
  149.         /* menus and cursors, and go away */
  150.         switch (typeToMake) {
  151.             case 'PICT':
  152.                 KillPicture((PicHandle)theData);
  153.                 InvalRect(&(*shortName)->selectionRect);
  154.                 gShowPub = false;
  155.                 (*shortName)->hasSelection = false;
  156.                 SetMyCursor(0);
  157.                 SwitchChecks(kSelectStuff);
  158.                 
  159.                 break;
  160.             case 'TEXT':
  161.                 DisposeHandle((*pubText)->theText);
  162.                 DisposeHandle((Handle)pubText);
  163.                 DisposeHandle(theData);
  164.                 break;
  165.             case kCustomType:
  166.                 break;
  167.         }
  168.         return;
  169.     }}
  170.     /* They clicked Publish.  First create the container (file) to hold the data */
  171.     /* See if thye are replacing a file */
  172.     if (!myreply.replacing) {
  173.         if (myErr = CreateEditionContainerFile(&myreply.container.theFile, 'CKH6', myreply.container.theFileScript)) {
  174.             ShowMe("\pCreateEditionContainerFIle", myErr);
  175.             return;
  176.         } 
  177.         } else {
  178.         /* they agreed to delete an existing file.  Kill it. */
  179.         FSpDelete(&myreply.container.theFile);
  180.         if (myErr = CreateEditionContainerFile(&myreply.container.theFile, 'CKH6', myreply.container.theFileScript)) {
  181.             ShowMe("\pCreateEditionContainerFIle", myErr);
  182.             return;
  183.  
  184.         }
  185.     }
  186.     /* now create the section record to describe this data to the edition manager */
  187.     /*  The section handle that is returned by this function will be the */
  188.     /* way that you will reference this edition for as long as the edition is */
  189.     /* active. */
  190.     /* The main way you'll keep track is through the section ID number. */
  191.     /* In this case, I have a base ID number for the window, and I just increment */
  192.     /* my general ID (gSectionID) every time I create an edition, and add it to the window ID.  */
  193.     if (GetHandleSize((Handle)(*shortName)->fileAliasHandle) == 0) {
  194.         myErr = NewSection(&myreply.container, nil, stPublisher, (*shortName)->windowID + gSectionID, pumOnSave, &gSecHandle);
  195.         /* nil for sectionDocument if it's never been saved */
  196.     } else {
  197.         /* if the file has been saved once, then we can store a reference to the 'parent' file */
  198.         /* in the edition */
  199.         FSSpec tempSpec;
  200.         Boolean myWasChanged;
  201.         myErr = ResolveAlias(nil, ((*shortName)->fileAliasHandle), &tempSpec, &myWasChanged);
  202.         myErr = NewSection(&myreply.container, &tempSpec, stPublisher, (*shortName)->windowID + gSectionID, pumOnSave,
  203.                            &gSecHandle);
  204.         
  205.     }
  206.     if (!myErr) {
  207.         /* put the section handle into our window structure */
  208.         (*gSecHandle)->refCon = kNeverSaved;                /*            meaning that this _document_ has not been saved */
  209.         /* put what type of thing this is in the refcon of the section handle */
  210.         switch (typeToMake) {
  211.             /* This is a little kludgy because I want to */
  212.             case 'PICT':
  213.                 (*gSecHandle)->refCon = kPictType;
  214.                 break;
  215.             case 'TEXT':
  216.                 (*gSecHandle)->refCon = kTextType;
  217.                 break;
  218.         }
  219.         StorePublisher(shortName, gSecHandle, &(*shortName)->selectionRect, pubText, typeToMake);
  220.     }
  221.     /* now write the data to the container */
  222.     MyWriteSection(gSecHandle, theData, typeToMake);
  223.     HUnlock(theData);
  224.     switch (typeToMake) {
  225.         case 'PICT':
  226.             KillPicture((PicHandle)theData);
  227.             break;
  228.         case 'TEXT':
  229.             break;
  230.         case kCustomType:
  231.             break;
  232.     }
  233.     (*shortName)->hasSelection = false;
  234.     InvalRect(&(*shortName)->selectionRect);                /* get rid of border once publish has happened */
  235.     gShowPub = false;
  236.     (*shortName)->hasSelection = false;
  237.     SetMyCursor(0);
  238.     SwitchChecks(kSelectStuff);
  239.     HUnlock((Handle)shortName);
  240. }
  241.  
  242. /* end CreatePublisher */
  243.  
  244. /* MyUpdateEdition publishes the latest data for this edition.  This will
  245. * be called when the user selects 'Send Edition Now' from the options
  246. * dialog, or when the document is saved (if automatic saving is 
  247. * enabled), or if a section write AppleEvent happens
  248. */
  249. OSErr MyUpdateEdition(SectionHandle theSection)
  250. {
  251.     WindowPtr tempCurrentWindow;
  252.     WindowPtr tempWindow;
  253.     Boolean tempSub, tempPub;
  254.     windowCHandle shortName;
  255.     SectionHandle *tempPtr;
  256.     register qq;
  257.     Rect *tempRectPtr;
  258.     extern Rect gShowPubRect;
  259.     extern Rect gShowSubRect;
  260.     GetPort(&tempWindow);
  261.     tempCurrentWindow = gCurrentWindow;
  262.     if (((*theSection)->refCon & 0xf) == kPictType) {
  263.         gCurrentWindow = FindSection(theSection);
  264.         HLock((Handle)theSection);
  265.         /* kill the borders, if any are showing right now */
  266.         tempSub = gShowSub;
  267.         tempPub = gShowPub;
  268.         if (gShowSub)
  269.             InvalRect(&gShowSubRect);
  270.         if (gShowPub)
  271.             InvalRect(&gShowPubRect);
  272.         gShowSub = gShowPub = false;
  273.         SetPort(gCurrentWindow);
  274.         shortName = (windowCHandle)GetWRefCon(gCurrentWindow);
  275.         HLock((Handle)shortName);
  276.         (ProcPtr)((*shortName)->drawMe)(shortName, gCurrentWindow);     /* draw without borders */
  277.         /* search this window for the section asked for */
  278.         HLock((*shortName)->pubs);
  279.         tempPtr = (SectionHandle *)*(*shortName)->pubs;
  280.         for (qq = 0; qq < (*shortName)->numPubs; qq++) {
  281.             HLock((Handle)*tempPtr);
  282.             if ((*theSection)->sectionID == (*(*tempPtr))->sectionID) {
  283.                 PicHandle tempPic;
  284.                 /* it's this one, grab the rect, pic it, publish it, and go away */
  285.                 HLock((*shortName)->pubRects);
  286.                 tempRectPtr = (Rect *)*(*shortName)->pubRects;
  287.                 tempRectPtr += qq;
  288.                 tempPic = MyMakePicture(tempRectPtr);
  289.                 HUnlock((*shortName)->pubRects);
  290.                 MyWriteSection(*tempPtr, (Handle)tempPic, 'PICT');
  291.                 KillPicture(tempPic);
  292.                 HUnlock((Handle)*tempPtr);
  293.                 break;
  294.             }
  295.         }
  296.         HUnlock((Handle)theSection);
  297.         HUnlock((Handle)shortName);
  298.     } else {
  299.         textSectionHandle theTS = TextSectionFromSecHandle(theSection);
  300.         /* it's a text pub */
  301.         MyWriteSection(theSection, (*theTS)->theText, 'TEXT');
  302.         
  303.     }
  304.     InvalRect(&gCurrentWindow->portRect);
  305.     gCurrentWindow = tempCurrentWindow;
  306.     SetPort(tempWindow);
  307.     return(noErr);
  308. }
  309.  
  310. /* end MyUpdateEdition */
  311.  
  312. /* MyMakePicture is a handy place to create our PICT demo data item.
  313. * It's called to create the actual edition data as well as the 'preview'
  314. * picture.
  315. */
  316. PicHandle MyMakePicture(Rect *thisRect)
  317. {
  318.     PicHandle thepic;
  319.     windowCHandle drawers;
  320.     Boolean tempPub, tempSub;
  321.     RgnHandle tempClip;
  322.     /* make sure borders aren't included in the picture */
  323.     tempPub = gShowPub;
  324.     tempSub = gShowSub;
  325.     gShowPub = false;
  326.     gShowSub = false;
  327.     tempClip = NewRgn();
  328.     GetClip(tempClip);
  329.     ClipRect(thisRect);
  330.     thepic = OpenPicture(thisRect);
  331.     drawers = (windowCHandle)GetWRefCon(gCurrentWindow);
  332.     HLock((Handle)drawers);
  333.     (ProcPtr)((*drawers)->drawMe)(drawers, gCurrentWindow);
  334.     HUnlock((Handle)drawers);
  335.     ClosePicture();
  336.     SetClip(tempClip);
  337.     DisposeRgn(tempClip);
  338.     /* restore old border states */
  339.     gShowPub = tempPub;
  340.     gShowSub = tempSub;
  341.     return(thepic);
  342. }
  343.  
  344. /* end MyMakePicture */
  345.  
  346. /* AEWriteSectionHandler is the AppleEvent handler for section write
  347. * events.   It first pulls the SectionHandle out of the AppleEvent record,
  348. * then verifies that this is a registered section (still active, not canceled)
  349. * and then calls MyUpdateEdition to write the edition
  350. */
  351. pascal OSErr AEWriteSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  352. {
  353. #pragma unused (reply,refIn)
  354.     SectionHandle theSection;
  355.     OSErr myErr;
  356.     myErr = GetSectionHandleFromEvent(messagein, &theSection);
  357.     if (myErr = IsRegisteredSection((SectionHandle)theSection)) {
  358.         ShowMe("\p Write IsRegisteredSection", myErr);
  359.         return(myErr);
  360.     }
  361.     MyUpdateEdition(theSection);
  362.     
  363. }
  364.  
  365. /* end AEWriteSectionHandler */
  366. /* •••• NEW EVENT •••• */
  367. /* •• Please read the description and code in the Inside Mac vol VI chapters on */
  368. /* the Edition Manager and APpleEvents for a full description */
  369. /* AECreatePubHandler handles the new create publisher event */
  370.  
  371. pascal OSErr AECreatePubHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  372. { windowCHandle tempWC;
  373. OSErr pubError = noErr;
  374. AliasHandle theAlias;
  375. Handle objectSpec;
  376. Size objectSize;
  377. DescType thisType;
  378. Size returnedSize;
  379. OSType theType;
  380. Boolean askForDialog;
  381. #define errAENoSuchObject 'noob'
  382. #define keyAEEditionFileLoc 'eloc'
  383. #define typeObjectSpecifier 'obj '
  384. /* this event has two parameters, a object specifier and an alias handle. */
  385. /* Both parameters are optional. */
  386. /* This sample application does not support the AppleEvents object model, so */
  387. /* we don't care about that parameter. */
  388. /* If you don't support the object model, then you need to check for a valid */
  389. /* current selection in the frontmost window */
  390. /* it's the same check we make to see if we should enable the 'Create Publisher' */
  391. /* menu item. */
  392. tempWC = (windowCHandle)GetWRefCon(FrontWindow());
  393. if (gHasSelection || HasTESelection(tempWC)){
  394. /* there is a valid selection. */
  395. /* get the alias handle from the event, if there is one */
  396. /* since we don't support the AE Object model yet, return an error if there is an object */
  397. /* spec contained in this event */
  398. pubError = AEGetParamPtr(messagein, keyDirectObject, typeObjectSpecifier, &thisType, (Ptr)&objectSpec,sizeof(Handle), &objectSize);
  399. if(pubError == noErr){
  400. /* no error means that there was an object specifier.  That's Bad.  return that we don't understand it */
  401. return(errAENoSuchObject);
  402. }
  403. pubError = AEGetParamPtr(messagein, keyAEEditionFileLoc, typeAlias, &thisType, (Ptr)&theAlias,sizeof(AliasHandle), &returnedSize);
  404. /* now pass to our publishing routine */
  405.  if (HasTESelection(tempWC))
  406.       theType ='TEXT';
  407.       else
  408.       theType ='PICT'; 
  409.  
  410.  
  411. pubError = CreatePublisher(theType,true,theAlias);
  412. } else {
  413. /* there was not a valid selection.  Return the errAENoSuchObject error, since this */
  414. /* makes the most sense in this situation, and when you do implement the objects you */
  415. /* will already be prepared.  Well, on one line of code at least.... */
  416. pubError= errAENoSuchObject;
  417. }
  418. return(pubError);
  419. }
  420. /* end AECreatePubHandler */
  421. /* AEScrollSectionHandler handles the scroll section event.  You'll get this
  422. * event when the user clicks 'Open Publisher' either from the 
  423. * Subcriber Options dialog, or from the Finder window.
  424. * This may also have happened after an ODOC AppleEvent, so 
  425. * don't assume anything about your state that wouldn't be true 
  426. * after an initial application launch
  427. */
  428. pascal OSErr AEScrollSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  429. {
  430. #pragma unused (reply,refIn)
  431.     WindowPtr tempWindow;
  432.     SectionHandle theSection;
  433.     OSErr myErr;
  434.     myErr = GetSectionHandleFromEvent(messagein, &theSection);
  435.     tempWindow = FindSection(theSection);
  436.     /* First bring our application to the front, then */
  437.     /* treat this the same way you would a click in a back window */
  438.     SetFrontProcess(&gOurSN);
  439.     if (tempWindow != nil)
  440.         ChangePlane(tempWindow);
  441.     return(noErr);
  442. }
  443.  
  444. /* end AEScrollSectionHandler */
  445.  
  446. /* AECancelSectionHandler cancels a current section, either a publisher
  447. * or subscriber.  This function pulls the section handle out of the 
  448. * AppleEvent, then dispatches to the proper cancel routine for a
  449. * pub or sub.
  450. */
  451. pascal OSErr AECancelSectionHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  452. {
  453. #pragma unused (reply,refIn)
  454.     SectionHandle theSection;
  455.     OSErr myErr;
  456.     myErr = GetSectionHandleFromEvent(messagein, &theSection);
  457.     myErr = IsRegisteredSection(theSection);
  458.     if (myErr != noErr)
  459.         return(myErr);                                      /* already killed by someone */
  460.     MyCancelSection(theSection, FindSection(theSection));
  461.     
  462. }
  463.  
  464. /* end AECancelSectionHandler */
  465.  
  466. /* MyWriteSection actually opens and writes the section data.  This will
  467. * be called in response to a click in 'Send Edition Now' in the pub options
  468. * box, from the section event 'write section', or when the file is being saved
  469. * and 'pumAuto' is enabled
  470. */
  471. OSErr MyWriteSection(SectionHandle secHandle, Handle theData, OSType theType)
  472. {
  473.     OSErr myErr;
  474.     /* update the time in the section handle please */
  475.     /* this tells the Edition Manager that the eidtion has changed, and */
  476.     /* to alert all the subscribers to the change */
  477.     SetCursor(*GetCursor(watchCursor));
  478.     HLock((Handle)secHandle);
  479.     GetDateTime(&(*secHandle)->mdDate);                     /* ••• Please see NOTE in main.c about mdDate (find mdDate) */
  480.     HUnlock((Handle)secHandle);
  481.     /* OpenNewEdition, _NOT_ OpenEdition.  You need to use OpenNewEdition */
  482.     /* to get write access and to let the Edition Manager determine if you */
  483.     /* are allowed to write to this section */
  484.     myErr = OpenNewEdition(secHandle, 'CKH6', nil, &gEdRefNum);
  485.     if (myErr)
  486.         ShowMe("\pOpenNewEdition", myErr);
  487.     HLock(theData);
  488.     /* And actually write the data (finally) */
  489.     
  490.     myErr = WriteEdition(gEdRefNum, theType, *theData, GetHandleSize(theData));
  491.     if (myErr)
  492.         ShowMe("\pWriteEdition", myErr);
  493.     if (myErr)
  494.         myErr = 0;
  495.     else
  496.         myErr = -1;
  497.     /* The Boolean tells the Edition Manager if you were successful in */
  498.     /* writing the data. */
  499.     myErr = CloseEdition(gEdRefNum, (Boolean)myErr);
  500.     return(myErr);
  501. }
  502.  
  503. /* end MyWriteSection */
  504.  
  505. /* StorePublisher moves the window data struct storing function to here */
  506. /* shortName is locked on entry */
  507. void StorePublisher(windowCHandle shortName, SectionHandle storeSection, Rect *inRect, textSectionHandle textIn, OSType typeIn)
  508. {
  509.     Rect *tempRectPtr;
  510.     SectionHandle *tempPtr;
  511.     OSErr myErr;
  512.     switch (typeIn) {
  513.         case 'PICT':
  514.             HUnlock((*shortName)->pubs);
  515.             MySetHandleSize((*shortName)->pubs, GetHandleSize((*shortName)->pubs) + sizeof(Handle));
  516.             myErr = MemError();
  517.             if (myErr)
  518.                 ShowMe("\pMemory", myErr);
  519.             HLock((*shortName)->pubs);
  520.             tempPtr = (SectionHandle *)((*(*shortName)->pubs) + (sizeof(Handle) * ((*shortName)->numPubs)));
  521.             *tempPtr = (SectionHandle)storeSection;
  522.             /* •••• NOTE, please look at the note in the Subscribe.c file concerning the dirty flag and  */
  523.             /* editions.  Open Subscribe.c and find the string 'Human Interface' */
  524.             /*    (*shortName)->windowDirty = true;  */
  525.             /* save the rectangle to show the published rectangle if the user wants to see it. */
  526.             HUnlock((*shortName)->pubRects);
  527.             MySetHandleSize((*shortName)->pubRects, (GetHandleSize((*shortName)->pubRects) + sizeof(Rect)));
  528.             myErr = MemError();
  529.             if (myErr)
  530.                 ShowMe("\pMemory", myErr);
  531.             HLock((*shortName)->pubRects);
  532.             tempRectPtr = (Rect *)*(*shortName)->pubRects;
  533.             tempRectPtr += (*shortName)->numPubs;
  534.             *tempRectPtr = *inRect;
  535.             (*shortName)->numPubs++;
  536.             HUnlock((*shortName)->pubRects);
  537.             HUnlock((*shortName)->pubs);
  538.             break;
  539.         case 'TEXT':
  540.             /* set my text section ID to the same as the actual section ID, again, it keeps */
  541.             /* dereferencing down */
  542.             (*textIn)->theID = (*storeSection)->sectionID;
  543.             /* tell myself that this is a publisher */
  544.             (*textIn)->publishing = true;
  545.             if ((*shortName)->textSections == nil) {
  546.                 (*shortName)->textSections = textIn;
  547.             } else {
  548.                 textSectionHandle tempTS = (*shortName)->textSections;
  549.                 while ((*tempTS)->nextSection != nil) {
  550.                     tempTS = (*tempTS)->nextSection;
  551.                 }
  552.                 (*tempTS)->nextSection = textIn;
  553.             }
  554.             (*textIn)->theSection = storeSection;
  555.             break;
  556.     }
  557.     gSectionID++;
  558. }
  559.  
  560. /* Find Section returns the window that this section is included in */
  561. /* Need to look in both the PICT and TEXT lists */
  562. WindowPtr FindSection(SectionHandle inSection)
  563. {
  564.     extern WindowPtr gActionWindows;
  565.     extern short gWindowCount;
  566.     long subIDtofind;
  567.     Boolean secFound = false;
  568.     SectionHandle *tempPtr;
  569.     SectionRecord *tempRecord;
  570.     Handle tempHandle;
  571.     WindowPtr tempNextWindow;
  572.     register qq, jj;
  573.     subIDtofind = (*inSection)->sectionID;
  574.     tempNextWindow = gActionWindows;                        /* start at the beginning of the chain */
  575.     for (qq = 0; qq < gWindowCount; qq++) {
  576.         windowCHandle tempWC;
  577.         /* do housekeeping to get to the section handle list */
  578.         tempWC = (windowCHandle)GetWRefCon(tempNextWindow);
  579.         HLock((Handle)tempWC);
  580.         if (((*inSection)->refCon & 0xf) == kPictType) {
  581.             tempHandle = (*tempWC)->pubs;                   /* handle containing SectionHandles */
  582.             HLock(tempHandle);
  583.             tempPtr = (SectionHandle *)*tempHandle;
  584.             /* Loop through all our sections until we find this edition */
  585.             for (jj = 0; jj < (*tempWC)->numPubs; jj++) {
  586.                 HLock((Handle)*tempPtr);
  587.                 tempRecord = *(*tempPtr);
  588.                 if (tempRecord->sectionID == subIDtofind) {
  589.                     HUnlock((Handle)*tempPtr);
  590.                     HUnlock((Handle)tempWC);
  591.                     return(tempNextWindow);
  592.                 } else {
  593.                     HUnlock((Handle)tempWC);
  594.                     HUnlock((Handle)*tempPtr);
  595.                     tempPtr += 1;
  596.                 }
  597.             }
  598.             HUnlock(tempHandle);
  599.             /* same thing for subscribers */
  600.             tempHandle = (*tempWC)->subs;                   /* handle containing SectionHandles */
  601.             HLock(tempHandle);
  602.             tempPtr = (SectionHandle *)*tempHandle;
  603.             /* Loop through all our sections until we find this edition */
  604.             for (jj = 0; jj < (*tempWC)->numSubs; jj++) {
  605.                 HLock((Handle)*tempPtr);
  606.                 tempRecord = *(*tempPtr);
  607.                 if (tempRecord->sectionID == subIDtofind) {
  608.                     HUnlock((Handle)*tempPtr);
  609.                     HUnlock((Handle)tempWC);
  610.                     return(tempNextWindow);
  611.                 } else {
  612.                     HUnlock((Handle)tempWC);
  613.                     HUnlock((Handle)*tempPtr);
  614.                     tempPtr += 1;
  615.                 }
  616.             }
  617.             HUnlock(tempHandle);
  618.         } else {
  619.             /* Look in the TEXT lists */
  620.             if ((*tempWC)->textSections) {
  621.                 textSectionHandle tempTS = (*tempWC)->textSections;
  622.                 do {
  623.                     if ((*((*tempTS)->theSection))->sectionID == subIDtofind) {
  624.                         HUnlock((Handle)tempWC);
  625.                         return(tempNextWindow);
  626.                     }
  627.                     tempTS = (*tempTS)->nextSection;
  628.                 } while (tempTS);
  629.                 
  630.             }
  631.         }
  632.         tempNextWindow = (*tempWC)->nextWindow;
  633.         
  634.         HUnlock((Handle)tempWC);
  635.     }
  636.     return(nil);
  637. }
  638.  
  639. pascal short ExpOptHook(short itemOffset, short itemHit, DialogPtr theDialog, Ptr yourDataPtr)
  640. {
  641.     short myHit;
  642.     short itemType;
  643.     ControlHandle theButton;
  644.     Rect theRect;
  645.     /* first make sure that a sub-dialog is not frontmost */
  646.     /* so we don't filter keys or hits to a sub-dialog */
  647.     if (GetWRefCon((WindowPtr)theDialog) == 'stdf' || GetWRefCon((WindowPtr)theDialog) == 'optn') {
  648.         /* only have one item in this expansion, but we'll check the range anyway */
  649.         myHit = itemHit - itemOffset;                       /* since our item numbers are relative to the total number */
  650.         /* of items in the dialog, and the system may change.  Always do your item numbering based */
  651.         /* on the offset, this will prevent incompatability when the system dialog grows or shrinks */
  652.         if (myHit == 1) {                                   /* I only added one item, so this be the one */
  653.             /* Pass itemHit here, not myHit, since the dialog manager has no idea that this is an */
  654.             /* additive dialog.  It is counting from the actual start of the DITL, not the start of */
  655.             /* your custom items */
  656.             GetDialogItem(theDialog, itemHit, &itemType, (Handle *)&theButton, &theRect);
  657.             if (GetControlValue(theButton))
  658.                 SetControlValue(theButton, false);
  659.             else
  660.                 SetControlValue(theButton, true);
  661.         }
  662.     }
  663.     return(itemHit);                                        /* the return value must be absolute */
  664. }
  665.  
  666. pascal Boolean ExpOptFilter(DialogPtr theDialog, EventRecord *theEvent, short itemOffset, short *itemHit, Ptr yourDataPtr)
  667. {
  668.     short myHit;
  669.     short itemType;
  670.     ControlHandle theButton;
  671.     Rect theRect;
  672.     /* first make sure that a sub-dialog is not frontmost */
  673.     /* so we don't filter keys or hits to a sub-dialog */
  674.     if (GetWRefCon((WindowPtr)theDialog) == 'stdf' || GetWRefCon((WindowPtr)theDialog) == 'optn') {
  675.         /* standard filter proc kinda stuff here */
  676.         if ((theEvent->what) == keyDown) {
  677.             char tempChar;
  678.             tempChar = theEvent->message & charCodeMask;
  679.             
  680.             if (((tempChar == 'A') || (tempChar == 'a')) && (theEvent->modifiers & cmdKey)) {
  681.                 /* they pressed an A with the command key down, we get to handle it. */
  682.                 GetDialogItem(theDialog, itemOffset + 1, &itemType, (Handle *)&theButton, &theRect);
  683.                 if (GetControlValue(theButton))
  684.                     SetControlValue(theButton, false);
  685.                 else
  686.                     SetControlValue(theButton, true);
  687.                 
  688.                 return(true);                               /* tell folks we handled it */
  689.             }
  690.         }
  691.     }
  692.     return(false);                                          /* was not a keystroke we wanted */
  693.     
  694. }
  695.  
  696. /* shortName is locked on entry */
  697. textSectionHandle GetTextSection(windowCHandle shortName, SectionType what)
  698. {
  699.     CharsHandle theRawText;
  700.     TEHandle tempTE;
  701.     textSectionHandle theTextSection;
  702.     short theLength;
  703.     Handle theSelection;
  704.     theTextSection = (textSectionHandle)NewHandle(sizeof(textSection));
  705.     HLock((Handle)theTextSection);
  706.     (*theTextSection)->bordered = gShowingAll;              /* create section reflecting current */
  707.     /* global border state */
  708.     tempTE = (*shortName)->boxHandle;
  709.     (*theTextSection)->startChar = (*tempTE)->selStart;
  710.     if (what == stPublisher) {
  711.         /* initialize it if it's a publisher */
  712.         (*theTextSection)->endChar = (*tempTE)->selEnd;
  713.         
  714.         theRawText = TEGetText(tempTE);
  715.         theSelection = NewHandle(((*tempTE)->selEnd) - ((*tempTE)->selStart));
  716.         
  717.         HLock(theSelection);
  718.         HLock((Handle)theRawText);
  719.         BlockMove((Ptr)*theRawText + (*tempTE)->selStart, (Ptr)*theSelection, (*tempTE)->selEnd - (*tempTE)->selStart);
  720.         HUnlock(theSelection);
  721.         HUnlock((Handle)theRawText);
  722.         (*theTextSection)->theText = theSelection;
  723.     } else {
  724.         /* set start same as end for subscribers */
  725.         (*theTextSection)->endChar = (*tempTE)->selStart;
  726.         (*theTextSection)->theText = NewHandle(0);
  727.     }
  728.     (*theTextSection)->nextSection = nil;
  729.     return(theTextSection);
  730. }
  731.  
  732. textSectionHandle TextSectionFromSecHandle(SectionHandle theSection)
  733. {
  734.     windowCHandle tempWC = (windowCHandle)GetWRefCon(FindSection(theSection));      /* gets the window it's in */
  735.     textSectionHandle tempTS = (*tempWC)->textSections;
  736.     unsigned long idToFind;
  737.     
  738.     idToFind = (*theSection)->sectionID;
  739.     /* find the ID that matches this thang */
  740.     do {
  741.         if ((*tempTS)->theID == idToFind)
  742.             return(tempTS);
  743.         tempTS = (*tempTS)->nextSection;
  744.     } while (tempTS);
  745.     return(nil);                                            /* failed */
  746. }
  747.  
  748.  
  749. #undef __PUBLISH__
  750.